#include "SmdPadCalculator.h"

#include <QtMath>

SmdPadCalculator::SmdPadCalculator(QObject *parent) : QObject(parent)
{
    clear();
}

SmdPadCalculator::~SmdPadCalculator()
{

}

bool SmdPadCalculator::calculate()
{
    const qreal lmin = leadSpanMin();
    const qreal lmax = leadSpanMax();
    const qreal tmin = leadWidthMin();
    const qreal tmax = leadWidthMax();
    const qreal wmin = leadHeightMin();
    const qreal wmax = leadHeightMax();

    qreal smax = lmax - 2.0*tmin;
    qreal smin = lmin - 2.0*tmax;
    qreal stol = smax -smin;
    qreal stolrms = qSqrt(qPow(lmax-lmin, 2) +
                          qPow(tmax-tmin, 2) +
                          qPow(tmax-tmin, 2));
    qreal sdiff = stol - stolrms;
    smax -= sdiff/2.0;
    smin += sdiff/2.0;

    qreal toetol = qSqrt(qPow(lmax-lmin, 2) +
                         qPow(2.0*fabricationTolerance(), 2) +
                         qPow(2.0*placementTolerance(), 2));
    qreal zmax = lmin + 2.0*toeGoal() + toetol;

    qreal heeltol = qSqrt(qPow(smax-smin, 2) +
                          qPow(2.0*fabricationTolerance(), 2) +
                          qPow(2.0*placementTolerance(), 2));
    qreal gmin = smax - 2.0*heelGoal() - heeltol;

    qreal sidetol = qSqrt(qPow(wmax-wmin, 2) +
                          qPow(2.0*fabricationTolerance(), 2) +
                          qPow(2.0*placementTolerance(), 2));
    qreal yref = wmin + 2.0*sideGoal() + sidetol;

    qreal c = qRound((zmax+gmin)/(2.0*positionRounding())) * positionRounding();
    qreal x = qRound((zmax-gmin)/(2.0*sizeRounding())) * sizeRounding();
    qreal y = qRound(yref/sizeRounding()) * sizeRounding();

    setPadSpacing(c);
    setPadWidth(x);
    setPadHeight(y);

    return true;
}

qreal SmdPadCalculator::leadSpanMin() const
{
    return m_leadSpanMin;
}

qreal SmdPadCalculator::leadSpanMax() const
{
    return m_leadSpanMax;
}

qreal SmdPadCalculator::leadWidthMin() const
{
    return m_leadWidthMin;
}

qreal SmdPadCalculator::leadWidthMax() const
{
    return m_leadWidthMax;
}

qreal SmdPadCalculator::leadHeightMin() const
{
    return m_leadHeightMin;
}

qreal SmdPadCalculator::leadHeightMax() const
{
    return m_leadHeightMax;
}

qreal SmdPadCalculator::fabricationTolerance() const
{
    return m_fabricationTolerance;
}

qreal SmdPadCalculator::placementTolerance() const
{
    return m_placementTolerance;
}

qreal SmdPadCalculator::toeGoal() const
{
    return m_toeGoal;
}

qreal SmdPadCalculator::heelGoal() const
{
    return m_heelGoal;
}

qreal SmdPadCalculator::sideGoal() const
{
    return m_sideGoal;
}

qreal SmdPadCalculator::positionRounding() const
{
    return m_positionRounding;
}

qreal SmdPadCalculator::sizeRounding() const
{
    return m_sizeRounding;
}

qreal SmdPadCalculator::padSpacing() const
{
    return m_padSpacing;
}

qreal SmdPadCalculator::padWidth() const
{
    return m_padWidth;
}

qreal SmdPadCalculator::padHeight() const
{
    return m_padHeight;
}

void SmdPadCalculator::setLeadSpanMin(qreal leadSpanMin)
{
    if (qFuzzyCompare(m_leadSpanMin, leadSpanMin))
        return;

    m_leadSpanMin = leadSpanMin;
    emit leadSpanMinChanged(leadSpanMin);
}

void SmdPadCalculator::setLeadSpanMax(qreal leadSpanMax)
{
    if (qFuzzyCompare(m_leadSpanMax, leadSpanMax))
        return;

    m_leadSpanMax = leadSpanMax;
    emit leadSpanMaxChanged(leadSpanMax);
}

void SmdPadCalculator::setLeadWidthMin(qreal leadWidthMin)
{
    if (qFuzzyCompare(m_leadWidthMin, leadWidthMin))
        return;

    m_leadWidthMin = leadWidthMin;
    emit leadWidthMinChanged(leadWidthMin);
}

void SmdPadCalculator::setLeadWidthMax(qreal leadWidthMax)
{
    if (qFuzzyCompare(m_leadWidthMax, leadWidthMax))
        return;

    m_leadWidthMax = leadWidthMax;
    emit leadWidthMaxChanged(leadWidthMax);
}

void SmdPadCalculator::setLeadHeightMin(qreal leadHeightMin)
{
    if (qFuzzyCompare(m_leadHeightMin, leadHeightMin))
        return;

    m_leadHeightMin = leadHeightMin;
    emit leadHeightMinChanged(leadHeightMin);
}

void SmdPadCalculator::setLeadHeightMax(qreal leadHeightMax)
{
    if (qFuzzyCompare(m_leadHeightMax, leadHeightMax))
        return;

    m_leadHeightMax = leadHeightMax;
    emit leadHeightMaxChanged(leadHeightMax);
}

void SmdPadCalculator::setFabricationTolerance(qreal fabricationTolerance)
{
    if (qFuzzyCompare(m_fabricationTolerance, fabricationTolerance))
        return;

    m_fabricationTolerance = fabricationTolerance;
    emit fabricationToleranceChanged(fabricationTolerance);
}

void SmdPadCalculator::setPlacementTolerance(qreal placementTolerance)
{
    if (qFuzzyCompare(m_placementTolerance, placementTolerance))
        return;

    m_placementTolerance = placementTolerance;
    emit placementToleranceChanged(placementTolerance);
}

void SmdPadCalculator::setToeGoal(qreal toeGoal)
{
    if (qFuzzyCompare(m_toeGoal, toeGoal))
        return;

    m_toeGoal = toeGoal;
    emit toeGoalChanged(toeGoal);
}

void SmdPadCalculator::setHeelGoal(qreal heelGoal)
{
    if (qFuzzyCompare(m_heelGoal, heelGoal))
        return;

    m_heelGoal = heelGoal;
    emit heelGoalChanged(heelGoal);
}

void SmdPadCalculator::setSideGoal(qreal sideGoal)
{
    if (qFuzzyCompare(m_sideGoal, sideGoal))
        return;

    m_sideGoal = sideGoal;
    emit sideGoalChanged(sideGoal);
}

void SmdPadCalculator::setPositionRounding(qreal positionRounding)
{
    if (qFuzzyCompare(m_positionRounding, positionRounding))
        return;

    m_positionRounding = positionRounding;
    emit positionRoundingChanged(positionRounding);
}

void SmdPadCalculator::setSizeRounding(qreal sizeRounding)
{
    if (qFuzzyCompare(m_sizeRounding, sizeRounding))
        return;

    m_sizeRounding = sizeRounding;
    emit sizeRoundingChanged(sizeRounding);
}

void SmdPadCalculator::clear()
{
    setLeadSpanMin(0.0);
    setLeadSpanMax(0.0);
    setLeadWidthMin(0.0);
    setLeadWidthMax(0.0);
    setLeadHeightMin(0.0);
    setLeadHeightMax(0.0);
    setFabricationTolerance(0.0);
    setPlacementTolerance(0.0);
    setToeGoal(0.0);
    setHeelGoal(0.0);
    setSideGoal(0.0);
    setPositionRounding(0.0);
    setSizeRounding(0.0);

    setPadSpacing(0.0);
    setPadWidth(0.0);
    setPadHeight(0.0);
}

void SmdPadCalculator::setPadSpacing(qreal padSpacing)
{
    if (qFuzzyCompare(m_padSpacing, padSpacing))
        return;

    m_padSpacing = padSpacing;
    emit padSpacingChanged(padSpacing);
}

void SmdPadCalculator::setPadWidth(qreal padWidth)
{
    if (qFuzzyCompare(m_padWidth, padWidth))
        return;

    m_padWidth = padWidth;
    emit padWidthChanged(padWidth);
}

void SmdPadCalculator::setPadHeight(qreal padHeight)
{
    if (qFuzzyCompare(m_padHeight, padHeight))
        return;

    m_padHeight = padHeight;
    emit padHeightChanged(padHeight);
}
